#include "StdAfx.h"

Loader* Singleton<Loader>::m_instance = 0;

void Loader::Update(float x, float y, float z)
{
	ui32 indexX = (ui32)floor(z / TILESIZE);
	ui32 indexZ = (ui32)floor(x / TILESIZE);
	ui32 flag = indexX * 100 + indexZ;
	if(m_models[1][1] != flag)
	{
		ui32 oiX = m_models[1][1] / 100;
		ui32 oiZ = m_models[1][1] - oiX * 100;
		if(oiX != indexX)
		{
			i32 diff = oiX - indexX;
			if(diff == -1)
			{
				sD3D.RemoveAdt(oiX - 1, oiZ);
				sD3D.RemoveAdt(oiX - 1, oiZ + 1);
				sD3D.RemoveAdt(oiX - 1, oiZ - 1);
				ui32 tmp[3][3];
				memcpy(tmp[0], m_models[1], 12);
				memcpy(tmp[1], m_models[2], 12);
				tmp[2][0] = m_models[2][0] + 100;
				tmp[2][1] = m_models[2][1] + 100;
				tmp[2][2] = m_models[2][2] + 100;
				memcpy(m_models, tmp, 36);
				LoadAdt(oiX + 2, oiZ);
				LoadAdt(oiX + 2, oiZ + 1);
				LoadAdt(oiX + 2, oiZ - 1);
			}
			else if(diff == 1)
			{
				sD3D.RemoveAdt(oiX + 1, oiZ);
				sD3D.RemoveAdt(oiX + 1, oiZ + 1);
				sD3D.RemoveAdt(oiX + 1, oiZ - 1);
				ui32 tmp[3][3];
				memcpy(tmp[2], m_models[1], 12);
				memcpy(tmp[1], m_models[0], 12);
				tmp[0][0] = m_models[0][0] - 100;
				tmp[0][1] = m_models[0][1] - 100;
				tmp[0][2] = m_models[0][2] - 100;
				memcpy(m_models, tmp, 36);
				LoadAdt(oiX - 2, oiZ);
				LoadAdt(oiX - 2, oiZ + 1);
				LoadAdt(oiX - 2, oiZ - 1);
			}
		}
		if(oiZ != indexZ)
		{
			i32 diff = oiZ - indexZ;
			if(diff == -1)
			{
				sD3D.RemoveAdt(oiX - 1, oiZ - 1);
				sD3D.RemoveAdt(oiX, oiZ - 1);
				sD3D.RemoveAdt(oiX + 1, oiZ - 1);
				for(ui32 i = 0; i < 3; ++i)
				{
					for(ui32 j = 0; j < 3; ++j)
						m_models[i][j] += 1;
				}
				try
				{
					LoadAdt(oiX + 1, oiZ + 2);
					LoadAdt(oiX, oiZ + 2);
					LoadAdt(oiX - 1, oiZ + 2);
				}
				catch(...)
				{
				}
			}
			else if(diff == 1)
			{
				sD3D.RemoveAdt(oiX - 1, oiZ + 1);
				sD3D.RemoveAdt(oiX, oiZ + 1);
				sD3D.RemoveAdt(oiX + 1, oiZ + 1);
				for(ui32 i = 0; i < 3; ++i)
				{
					for(ui32 j = 0; j < 3; ++j)
						m_models[i][j] -= 1;
				}
				try
				{
					LoadAdt(oiX + 1, oiZ - 2);
					LoadAdt(oiX, oiZ - 2);
					LoadAdt(oiX - 1, oiZ - 2);
				}
				catch(...)
				{
				}
			}
		}
	}
}

void AsyncLoadADT(ADTModel* model)
{
	if(model->Init())
		sD3D.AddAdt(model, model->m_indexX, model->m_indexZ);
}

unsigned long __stdcall LoadAdtProc(LPVOID data)
{
	ui32 combined = (ui32)data;
	ui32 map = combined / 10000;
	ui32 ofsX = (combined - (map * 10000)) / 100;
	ui32 ofsZ = combined - (ofsX * 100) - (map * 10000);
	switch(map)
	{
	case 0:
		{
			char path[255];
			sprintf_s<255>(path, "World\\Maps\\Kalimdor\\Kalimdor_%u_%u.adt", ofsX, ofsZ);
			ADTModel* model = new ADTModel(path);
			model->m_indexX = ofsX;
			model->m_indexZ = ofsZ;
			AsyncLoadADT(model);
			break;
		}
	case 1:
		{
			char path[255];
			sprintf_s<255>(path, "World\\Maps\\Azeroth\\Azeroth_%u_%u.adt", ofsX, ofsZ);
			ADTModel* model = new ADTModel(path);
			model->m_indexX = ofsX;
			model->m_indexZ = ofsZ;
			AsyncLoadADT(model);
			break;
		}
	case 2:
		{
			char path[255];
			sprintf_s<255>(path, "World\\Maps\\Expansion01\\Expansion01_%u_%u.adt", ofsX, ofsZ);
			ADTModel* model = new ADTModel(path);
			model->m_indexX = ofsX;
			model->m_indexZ = ofsZ;
			AsyncLoadADT(model);
			break;
		}
	case 3:
		{
			char path[255];
			sprintf_s<255>(path, "World\\Maps\\Northrend\\Northrend_%u_%u.adt", ofsX, ofsZ);
			ADTModel* model = new ADTModel(path);
			model->m_indexX = ofsX;
			model->m_indexZ = ofsZ;
			AsyncLoadADT(model);
			break;
		}
	}
	ExitThread(0);
}

void Loader::LoadAdt(ui32 x, ui32 y)
{
	ui32 param = m_mapId * 10000 + x * 100 + y;
	CreateThread(0, 0, LoadAdtProc, (LPVOID)param, 0, 0);
}